#include "bsp_config.h"
#include "es_oled.h"
#include "es_uart.h"


#if USING_SERIAL_DEBUG
/**
  * @brief  实现 rt_hw_console_getchar, 获取字符
  * @param  None
  * @retval char: 串口接收到的数据
  *
  * @attention	在未获取到字符时，需要让出 CPU
  * 
  */
#if FINSGH_USING_INTERRUPT

rt_uint8_t uart_rx_buf[UART_RX_BUF_LEN] = {0};
struct rt_ringbuffer  uart_rxcb;         /* 定义一个 ringbuffer cb */
static struct rt_semaphore shell_rx_sem; /* 定义一个静态信号量 */

rt_inline enum rt_ringbuffer_state rt_ringbuffer_status(struct rt_ringbuffer *rb)
{
    if (rb->read_index == rb->write_index)
    {
        if (rb->read_mirror == rb->write_mirror)
            return RT_RINGBUFFER_EMPTY;
        else
            return RT_RINGBUFFER_FULL;
    }
    return RT_RINGBUFFER_HALFFULL;
}

/**
 * get the size of data in rb
 */
rt_size_t rt_ringbuffer_data_len(struct rt_ringbuffer *rb)
{
    switch (rt_ringbuffer_status(rb))
    {
    case RT_RINGBUFFER_EMPTY:
        return 0;
    case RT_RINGBUFFER_FULL:
        return rb->buffer_size;
    case RT_RINGBUFFER_HALFFULL:
    default:
        if (rb->write_index > rb->read_index)
            return rb->write_index - rb->read_index;
        else
            return rb->buffer_size - (rb->read_index - rb->write_index);
    };
}

void rt_ringbuffer_init(struct rt_ringbuffer *rb,
                        rt_uint8_t           *pool,
                        rt_int16_t            size)
{
    RT_ASSERT(rb != RT_NULL);
    RT_ASSERT(size > 0);

    /* initialize read and write index */
    rb->read_mirror = rb->read_index = 0;
    rb->write_mirror = rb->write_index = 0;

    /* set buffer pool and size */
    rb->buffer_ptr = pool;
    rb->buffer_size = RT_ALIGN_DOWN(size, RT_ALIGN_SIZE);
}

/**
 * put a character into ring buffer
 */
rt_size_t rt_ringbuffer_putchar(struct rt_ringbuffer *rb, const rt_uint8_t ch)
{
    RT_ASSERT(rb != RT_NULL);

    /* whether has enough space */
    if (!rt_ringbuffer_space_len(rb))
        return 0;

    rb->buffer_ptr[rb->write_index] = ch;

    /* flip mirror */
    if (rb->write_index == rb->buffer_size-1)
    {
        rb->write_mirror = ~rb->write_mirror;
        rb->write_index = 0;
    }
    else
    {
        rb->write_index++;
    }

    return 1;
}
/**
 * get a character from a ringbuffer
 */
rt_size_t rt_ringbuffer_getchar(struct rt_ringbuffer *rb, rt_uint8_t *ch)
{
    RT_ASSERT(rb != RT_NULL);

    /* ringbuffer is empty */
    if (!rt_ringbuffer_data_len(rb))
        return 0;

    /* put character */
    *ch = rb->buffer_ptr[rb->read_index];

    if (rb->read_index == rb->buffer_size-1)
    {
        rb->read_mirror = ~rb->read_mirror;
        rb->read_index = 0;
    }
    else
    {
        rb->read_index++;
    }

    return 1;
}

void getchar_irq_init(void){
    /* 初始化串口接收 ringbuffer  */
    rt_ringbuffer_init(&uart_rxcb, uart_rx_buf, UART_RX_BUF_LEN);

    /* 初始化串口接收数据的信号量 */
    rt_sem_init(&(shell_rx_sem), "shell_rx", 0, 0);
}

/* 中断方式 */
char rt_hw_console_getchar(void)
{
    char ch = 0;

    /* 从 ringbuffer 中拿出数据 */
    while (rt_ringbuffer_getchar(&uart_rxcb, (rt_uint8_t *)&ch) != 1)
    {
        rt_sem_take(&shell_rx_sem, RT_WAITING_FOREVER);
    }
    return ch;
}

/* uart 中断 */
void DEBUG_USART_IRQHandler(void)
{
    int ch = -1;
    /* enter interrupt */
    rt_interrupt_enter();          //在中断中一定要调用这对函数，进入中断

    if ((USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_RXNE) != RESET) &&
        (USART_GetITStatus(DEBUG_USARTx, USART_IT_RXNE) != RESET))
    {
        while (1)
        {
            ch = -1;
            if (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_RXNE) != RESET)
            {
                ch =  DEBUG_USARTx->DR & 0xff;
            }
            if (ch == -1)
            {
                break;
            }
            /* 读取到数据，将数据存入 ringbuffer */
            rt_ringbuffer_putchar(&uart_rxcb, ch);
        }
        rt_sem_release(&shell_rx_sem);
    }

    /* leave interrupt */
    rt_interrupt_leave();    //在中断中一定要调用这对函数，离开中断
}
#else
/* 查询方式 */
char rt_hw_console_getchar(void)
{
    int ch = -1;

    if (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_RXNE) != RESET)
    {
        ch = DEBUG_USARTx->DR & 0xff;
    }
    else
    {
        if(USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_ORE) != RESET)
        {
            USART_ClearFlag(DEBUG_USARTx, USART_FLAG_ORE);
        }
        rt_thread_delay(10);
    }
    return ch;
}
#endif
#endif

/**
  * @brief  重映射串口DEBUG_USARTx到rt_kprintf()函数
  *   			Note：DEBUG_USARTx是在bsp_usart.h中定义的宏
  * @param  str：要输出到串口的字符串
  * @retval 无
  *
  * @attention
  * 
  */
void rt_hw_console_output(const char *str)
{	
#ifdef	USING_OLED_DEBUG
	const char *str_cy = str;
	static u8 x = 0, y = 0;
	
	while (*str_cy!='\0')
	{
		if (x > 122)
		{
			x = 0; y++;
		}
		if(y > 7)
		{
			x = y = 0;
			OLED_CLS();
		}
		
		if(*str_cy=='\n'){
			x = 0; y++;	str_cy++;
		}
		else if(*str_cy=='\b'){
			x -= 6;
			OLED_ShowChar(x, y, ' ');	
			str_cy++;
		}else{
			OLED_ShowChar(x, y, *str_cy++);
			x += 6;	
		}
	}
#endif
	
#ifdef USING_SERIAL_DEBUG
	/* 进入临界段 */
		rt_enter_critical();	
	
	/* 直到字符串结束 */
	while (*str!='\0')
	{
		/* 换行 */
    if (*str=='\n')
		{
			USART_SendData(DEBUG_USARTx, '\r'); 
			while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_TXE) == RESET);
		}
		
		USART_SendData(DEBUG_USARTx, *str++); 				
		while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_TXE) == RESET);	
	}	

	/* 退出临界段 */
    rt_exit_critical();
#endif
}
